from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.middleware.cors import CORSMiddleware
from sqlalchemy.orm import Session
from jose import JWTError, jwt
from passlib.context import CryptContext
from datetime import datetime, timedelta
from typing import List, Optional
import models
import schemas
from database import engine, get_db

# 创建数据库表
models.Base.metadata.create_all(bind=engine)

app = FastAPI(title="农场购物API")

# CORS配置
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # 在生产环境中应指定具体的前端域名
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# 认证相关配置
SECRET_KEY = "your-secret-key-keep-it-safe"  # 生产环境中应使用更安全的密钥
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

# 认证工具函数
def verify_password(plain_password, hashed_password):
    return pwd_context.verify(plain_password, hashed_password)

def get_password_hash(password):
    return pwd_context.hash(password)

def get_user(db: Session, email: str):
    return db.query(models.User).filter(models.User.email == email).first()

def authenticate_user(db: Session, email: str, password: str):
    user = get_user(db, email)
    if not user:
        return False
    if not verify_password(password, user.hashed_password):
        return False
    return user

def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.datetime.utcnow() + expires_delta
    else:
        expire = datetime.datetime.utcnow() + timedelta(minutes=15)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt

# OAuth2密码流
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

async def get_current_user(db: Session = Depends(get_db), token: str = Depends(oauth2_scheme)):
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="无法验证凭据",
        headers={"WWW-Authenticate": "Bearer"},
    )
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        email: str = payload.get("sub")
        if email is None:
            raise credentials_exception
        token_data = schemas.TokenData(email=email)
    except JWTError:
        raise credentials_exception
    user = get_user(db, email=token_data.email)
    if user is None:
        raise credentials_exception
    return user

# 初始化示例数据
def init_db(db: Session = Depends(get_db)):
    # 检查是否已有数据
    if db.query(models.Product).count() == 0:
        # 添加示例商品
        sample_products = [
            {
                "id": 1,
                "name": "无线蓝牙耳机",
                "price": 299.99,
                "original_price": 399.99,
                "image": "https://picsum.photos/id/1/300/300",
                "rating": 4.5,
                "reviews": 120,
                "category": "电子产品",
                "is_new": True,
                "date_added": datetime.datetime(2023, 11, 15)
            },
            {
                "id": 2,
                "name": "纯棉T恤",
                "price": 59.99,
                "original_price": 89.99,
                "image": "https://picsum.photos/id/21/300/300",
                "rating": 4.2,
                "reviews": 86,
                "category": "服装鞋帽",
                "is_hot": True,
                "date_added": datetime.datetime(2023, 10, 20)
            },
            {
                "id": 3,
                "name": "智能手表",
                "price": 599.99,
                "original_price": 699.99,
                "image": "https://picsum.photos/id/96/300/300",
                "rating": 4.8,
                "reviews": 215,
                "category": "电子产品",
                "is_hot": True,
                "date_added": datetime.datetime(2023, 11, 5)
            },
            {
                "id": 4,
                "name": "北欧风格台灯",
                "price": 129.99,
                "original_price": 159.99,
                "image": "https://picsum.photos/id/116/300/300",
                "rating": 4.3,
                "reviews": 54,
                "category": "家居用品",
                "date_added": datetime.datetime(2023, 10, 10)
            },
            {
                "id": 5,
                "name": "机械键盘",
                "price": 199.99,
                "original_price": 249.99,
                "image": "https://picsum.photos/id/160/300/300",
                "rating": 4.7,
                "reviews": 143,
                "category": "电子产品",
                "date_added": datetime.datetime(2023, 11, 1)
            },
            {
                "id": 6,
                "name": "牛仔裤",
                "price": 149.99,
                "original_price": 199.99,
                "image": "https://picsum.photos/id/1059/300/300",
                "rating": 4.4,
                "reviews": 98,
                "category": "服装鞋帽",
                "date_added": datetime.datetime(2023, 9, 5)
            },
            {
                "id": 7,
                "name": "精装图书",
                "price": 49.99,
                "original_price": 69.99,
                "image": "https://picsum.photos/id/24/300/300",
                "rating": 4.9,
                "reviews": 76,
                "category": "图书音像",
                "is_new": True,
                "date_added": datetime.datetime(2023, 11, 20)
            },
            {
                "id": 8,
                "name": "便携式充电宝",
                "price": 89.99,
                "original_price": 129.99,
                "image": "https://picsum.photos/id/180/300/300",
                "rating": 4.1,
                "reviews": 102,
                "category": "电子产品",
                "date_added": datetime.datetime(2023, 8, 15)
            }
        ]
        
        for product in sample_products:
            db_product = models.Product(**product)
            db.add(db_product)
        db.commit()

# 路由
@app.on_event("startup")
def on_startup():
    db = next(get_db())
    init_db(db)

@app.post("/token", response_model=schemas.Token)
def login_for_access_token(db: Session = Depends(get_db), form_data: OAuth2PasswordRequestForm = Depends()):
    user = authenticate_user(db, form_data.username, form_data.password)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="用户名或密码不正确",
            headers={"WWW-Authenticate": "Bearer"},
        )
    access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    access_token = create_access_token(
        data={"sub": user.email}, expires_delta=access_token_expires
    )
    return {"access_token": access_token, "token_type": "bearer"}

@app.post("/users/", response_model=schemas.User)
def create_user(user: schemas.UserCreate, db: Session = Depends(get_db)):
    db_user = get_user(db, email=user.email)
    if db_user:
        raise HTTPException(status_code=400, detail="邮箱已被注册")
    hashed_password = get_password_hash(user.password)
    db_user = models.User(name=user.name, email=user.email, hashed_password=hashed_password)
    db.add(db_user)
    db.commit()
    db.refresh(db_user)
    return db_user

@app.get("/users/me/", response_model=schemas.User)
def read_users_me(current_user: schemas.User = Depends(get_current_user)):
    return current_user

@app.get("/products/")
def read_products(
    category: str = "all",
    skip: int = 0,
    limit: int = 4,
    db: Session = Depends(get_db)
):
    query = db.query(models.Product)
    
    if category != "all":
        if category == "new":
            query = query.filter(models.Product.is_new == True)
        elif category == "hot":
            query = query.filter(models.Product.is_hot == True)
        else:
            query = query.filter(models.Product.category == category)
    
    products = query.offset(skip).limit(limit).all()
    total = query.count()
    return {"products": products, "total": total}

@app.get("/products/{product_id}")
def read_product(product_id: int, db: Session = Depends(get_db)):
    product = db.query(models.Product).filter(models.Product.id == product_id).first()
    if product is None:
        raise HTTPException(status_code=404, detail="商品不存在")
    return product

@app.get("/cart/")
def read_cart(current_user: schemas.User = Depends(get_current_user), db: Session = Depends(get_db)):
    cart_items = db.query(models.CartItem).filter(models.CartItem.owner_id == current_user.id).all()
    
    # 获取商品详情
    items_with_details = []
    for item in cart_items:
        product = db.query(models.Product).filter(models.Product.id == item.product_id).first()
        if product:
            items_with_details.append({
                "cart_item_id": item.id,
                "product": product,
                "quantity": item.quantity
            })
    
    return {"items": items_with_details}

@app.post("/cart/")
def add_to_cart(
    cart_item: schemas.CartItemCreate,
    current_user: schemas.User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    # 检查商品是否存在
    product = db.query(models.Product).filter(models.Product.id == cart_item.product_id).first()
    if not product:
        raise HTTPException(status_code=404, detail="商品不存在")
    
    # 检查购物车中是否已有该商品
    existing_item = db.query(models.CartItem).filter(
        models.CartItem.owner_id == current_user.id,
        models.CartItem.product_id == cart_item.product_id
    ).first()
    
    if existing_item:
        # 更新数量
        existing_item.quantity += cart_item.quantity
        db.commit()
        db.refresh(existing_item)
        return existing_item
    else:
        # 添加新商品
        db_item = models.CartItem(
            product_id=cart_item.product_id,
            quantity=cart_item.quantity,
            owner_id=current_user.id
        )
        db.add(db_item)
        db.commit()
        db.refresh(db_item)
        return db_item

@app.put("/cart/{item_id}")
def update_cart_item(
    item_id: int,
    quantity: int,
    current_user: schemas.User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    if quantity <= 0:
        raise HTTPException(status_code=400, detail="数量必须大于0")
    
    item = db.query(models.CartItem).filter(
        models.CartItem.id == item_id,
        models.CartItem.owner_id == current_user.id
    ).first()
    
    if not item:
        raise HTTPException(status_code=404, detail="购物车项不存在")
    
    item.quantity = quantity
    db.commit()
    db.refresh(item)
    return item

@app.delete("/cart/{item_id}")
def remove_from_cart(
    item_id: int,
    current_user: schemas.User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    item = db.query(models.CartItem).filter(
        models.CartItem.id == item_id,
        models.CartItem.owner_id == current_user.id
    ).first()
    
    if not item:
        raise HTTPException(status_code=404, detail="购物车项不存在")
    
    db.delete(item)
    db.commit()
    return {"detail": "商品已从购物车中移除"}

@app.post("/checkout/")
def checkout(current_user: schemas.User = Depends(get_current_user), db: Session = Depends(get_db)):
    # 清空购物车并返回订单信息
    cart_items = db.query(models.CartItem).filter(models.CartItem.owner_id == current_user.id).all()
    
    if not cart_items:
        raise HTTPException(status_code=400, detail="购物车为空")
    
    # 计算总价
    total = 0
    for item in cart_items:
        product = db.query(models.Product).filter(models.Product.id == item.product_id).first()
        if product:
            total += product.price * item.quantity
    
    # 清空购物车
    for item in cart_items:
        db.delete(item)
    db.commit()
    
    return {
        "detail": "订单创建成功",
        "total": total,
        "order_id": f"ORD-{datetime.datetime.now().strftime('%Y%m%d%H%M%S')}-{current_user.id}"
    }